package com.cuhk.gulimall.member.service.impl;

import com.cuhk.common.exception.BizCodeEnum;
import com.cuhk.gulimall.member.dao.MemberLevelDao;
import com.cuhk.gulimall.member.entity.MemberLevelEntity;
import com.cuhk.gulimall.member.exception.NoMemberFoundException;
import com.cuhk.gulimall.member.exception.NoUniqueMemberNameException;
import com.cuhk.gulimall.member.exception.NoUniqueMemberPhoneException;
import com.cuhk.gulimall.member.exception.PasswordNotFoundException;
import com.cuhk.gulimall.member.vo.MemberLoginVo;
import com.cuhk.gulimall.member.vo.MemberRegisterVo;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.stereotype.Service;

import java.util.HashMap;
import java.util.Map;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.cuhk.common.utils.PageUtils;
import com.cuhk.common.utils.Query;

import com.cuhk.gulimall.member.dao.MemberDao;
import com.cuhk.gulimall.member.entity.MemberEntity;
import com.cuhk.gulimall.member.service.MemberService;
import org.springframework.transaction.annotation.Transactional;


@Service("memberService")
public class MemberServiceImpl extends ServiceImpl<MemberDao, MemberEntity> implements MemberService {

    @Autowired
    private MemberLevelDao memberLevelDao;

    @Autowired
    private MemberDao memberDao;

    @Override
    public PageUtils queryPage(Map<String, Object> params) {
        IPage<MemberEntity> page = this.page(
                new Query<MemberEntity>().getPage(params),
                new QueryWrapper<MemberEntity>()
        );

        return new PageUtils(page);
    }

    public MemberServiceImpl() {
        super();
    }

    @Transactional(rollbackFor = {NoUniqueMemberNameException.class, NoUniqueMemberPhoneException.class})
    @Override
    public void saveMember(MemberRegisterVo memberRegisterVo) {
        MemberLevelEntity memberLevelEntity = memberLevelDao.selectDefault();
        MemberEntity memberEntity = new MemberEntity();

        // 设置level_id
        if(memberLevelEntity != null) {
            memberEntity.setId(memberLevelEntity.getId());
        }

        // 设置用户名和注册手机号的重复性
        checkMemberNameUnique(memberRegisterVo.getUsername());
        checkMemberPhoneUnique(memberRegisterVo.getPhoneNumber());

        memberEntity.setUsername(memberRegisterVo.getUsername());
        memberEntity.setPassword(memberRegisterVo.getPassword());
        memberEntity.setMobile(memberRegisterVo.getPhoneNumber());

        // 加密密码
        // 加密策略：MD5加密算法 + 随机盐避免彩虹表暴力破解
        // springframework.security包下提供的BCryptPasswordEncoder类的encode方法
        // 可以直接实现+盐和md5加密的全过程
        // 在判断用户输入密码是否正确时，只需要调用match方法，传入明文和密文即可
        // BCryptPasswordEncoder的match方法的底层实现，可以根据密文中保留的一些定位信息，分离出盐，将盐和明文组合计算一遍md5，和密文比较
        BCryptPasswordEncoder encoder = new BCryptPasswordEncoder();
        String encodedPassword = encoder.encode(memberRegisterVo.getPassword());
        memberEntity.setPassword(encodedPassword);

        // 保存会员实体
        this.baseMapper.insert(memberEntity);

    }

    @Override
    public void checkMemberNameUnique(String memberName) throws NoUniqueMemberNameException {
        if(memberDao.selectByUsername(memberName) != 0) {
            throw new NoUniqueMemberNameException("用户名已存在! 烦请重新设置");
        }
    }

    @Override
    public void checkMemberPhoneUnique(String memberPhone) throws NoUniqueMemberPhoneException {
        if(memberDao.selectByMobile(memberPhone) != 0) {
            throw new NoUniqueMemberPhoneException("手机号已被注册! 烦请更换注册号码");
        }
    }

    @Override
    public void loginMember(MemberLoginVo memberLoginVo) throws NoMemberFoundException, PasswordNotFoundException {
        MemberEntity memberEntity = memberDao.selectByNameOrMobile(memberLoginVo.getUsername());
        if(memberEntity == null) {
            throw new NoMemberFoundException("用户不存在");
        }
        // 验证密码正确性
        String passwordFromDB = memberEntity.getPassword();
        String passwordFromUser = memberLoginVo.getPassword();
        BCryptPasswordEncoder encoder = new BCryptPasswordEncoder();
        if(!encoder.matches(passwordFromUser, passwordFromDB)) {
            throw new PasswordNotFoundException("密码填写不正确");
        }
    }
}